package com.ruoyi.alipay.redisAop;

import com.ruoyi.alipay.common.ApiIdempotent;
import com.ruoyi.alipay.util.RedisLock;
import com.ruoyi.common.core.utils.IdUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Slf4j
@Aspect
@Component
public class ApidempotentAspect {

    @Autowired
    private RedisLock redisLock;

    @Pointcut("@annotation(com.ruoyi.alipay.common.ApiIdempotent)")
    public void apidempotent(){}

    @Around("apidempotent()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 使用分布式锁 机制-实现
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        ApiIdempotent apiIdempotent = method.getAnnotation(ApiIdempotent.class);
        int lockSeconds = apiIdempotent.lockTime();

//        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//        AssertUtils.notNull(request, "request can not null");

        // 获取请求的凭证，本项目中使用的JWT,可对应修改
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("token");
        String requestURI = request.getRequestURI();
                int i=0;
        String key = getIdeKey(token, requestURI);
        String clientId = IdUtils.randomUUID();
       // System.out.println("===============================获取锁");
        // 获取锁
        boolean lock = redisLock.tryLock(key, clientId, lockSeconds);
       // boolean lock = redisLock.tryLock("mock", "lock", 1);
        log.info("tryLock key = [{}], clientId = [{}]", key, clientId);
        System.out.println(i);
        if (lock) {
            i++;
            System.out.println("获取成功=================================="+i);
            log.info("tryLock success, key = [{}], clientId = [{}]", key, clientId);
            // 获取锁成功
            Object result;
            try {
                // 执行进程
                result = joinPoint.proceed();
            } finally {
                // 解锁
                Thread.sleep(3000);
                redisLock.releaseLock(key, clientId);
                log.info("releaseLock success, key = [{}], clientId = [{}]", key, clientId);
            }
            return result;
        } else {
            // 获取锁失败，认为是重复提交的请求
            log.info("tryLock fail, key = [{}]", key);
            throw  new RuntimeException("重复请求，请稍后再试!");
        }
    }

    private String getIdeKey(String token, String requestURI) {
        return "redisLock:" + token + requestURI;
    }

}